﻿using Entity;
using Entity.Attributes;
using IBLL;
using Qiao.Common.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;

namespace 反射
{
    class Program
    {
        /// <summary>
        /// 目标把所有涉及到反射的内置方法都用一边。
        /// 并且使用反射创建对象，调用各种方法，无参，有参，有默认参数的方法，泛型方法。
        /// 有参: int string class 枚举 泛型 动态 默认 结构
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            // 获取程序的基目录，结尾包含\
            var a = AppDomain.CurrentDomain.BaseDirectory;
            var bllConfig = ConfigHelper.GetConfigString("BLLName");
            ///反射就是用来读取DLL中的信息和使用。
            ///加载DLL,下面三个一样，只不过加载DLL的方式不一样
            ///Load 通过程序集名称加载DLL  BLL.One
            ///LoadFile 通过程序集的结对路径加载DLL  F:\02.Git\Qiao.Basics\反射\反射\bin\Debug\BLL.One.dll
            ///LoadFrom 通过DLL全称加载DLL  BLL.One.dll
            ///他们三个不需要管该程序集在系统中是否添加引用。

            Assembly assembly = Assembly.Load(bllConfig);
            Assembly assembly1 = Assembly.LoadFile(a + "\\" + bllConfig + ".dll");
            Assembly assembly2 = Assembly.LoadFrom(bllConfig + ".dll");
            {
                #region Assembly中所有的属性  基本没有发现有啥用

                ///程序集全称
                ///"BLL.One, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                var temp1 = assembly.FullName;
                ///程序集绝对路径
                ///"file:///F:/02.Git/Qiao.Basics/反射/反射/bin/Debug/BLL.One.DLL"
                var temp2 = assembly.CodeBase;
                ///程序集特性
                ///集合
                var temp3 = assembly.CustomAttributes;
                var temp4 = assembly.DefinedTypes;
                var temp5 = assembly.EntryPoint;
                var temp6 = assembly.EscapedCodeBase;
                var temp7 = assembly.Evidence;
                var temp8 = assembly.ExportedTypes;
                var temp9 = assembly.GlobalAssemblyCache;
                var tmep10 = assembly.HostContext;
                var temp11 = assembly.ImageRuntimeVersion;
                var temp12 = assembly.IsDynamic;
                var temp13 = assembly.IsFullyTrusted;
                ///程序集绝对路径
                ///"file:///F:/02.Git/Qiao.Basics/反射/反射/bin/Debug/BLL.One.DLL"
                var temp14 = assembly.Location;
                var tmep15 = assembly.ManifestModule;
                var temp16 = assembly.Modules;
                var temp17 = assembly.PermissionSet;
                var temp18 = assembly.ReflectionOnly;
                var temp19 = assembly.SecurityRuleSet;

                #endregion

                #region Assembly中所有的方法

                #region assembly.CreateInstance 创建对象
                object o = assembly.CreateInstance("BLL.One.Student");
                //IStudent student = o as IStudent;
                //student.GetStudent();
                #endregion

                #region assembly.GetCustomAttribute 获取DLL中的特性
                var attributeList1 = assembly.GetCustomAttributes();
                //这个 true和false一样不知道为啥
                var attributeList2 = assembly.GetCustomAttributes(true);
                var attributeList3 = assembly.GetCustomAttributes(typeof(System.Reflection.AssemblyCompanyAttribute));
                var attributeList4 = assembly.GetCustomAttributes(typeof(Attribute), true);
                var attributeList5 = assembly.GetCustomAttributes<AssemblyCompanyAttribute>();

                var attribute1 = assembly.GetCustomAttribute(typeof(AssemblyCompanyAttribute));
                var attribute2 = assembly.GetCustomAttribute<AssemblyCompanyAttribute>();

                var attributeList6 = assembly.GetCustomAttributesData();

                #endregion

                #region assembly.GetExportedTypes  最后输出类型
                var exportedTypes = assembly.GetExportedTypes();
                #endregion

                #region assembly.GetLoadedModules  获取DLL中的模块列表，通过IDE编译的DLL之后有一个模块
                var modules1 = assembly.GetLoadedModules();
                var modules2 = assembly.GetLoadedModules(true);
                var modules3 = assembly.GetLoadedModules(false);
                #endregion

                #region assembly.GetType 获取DLL中所有或者指定的类型
                var typeList1 = assembly.GetTypes();
                var type1 = assembly.GetType();
                var type2 = assembly.GetType("BLL.One.Student");
                ///是否抛异常 true 抛 false 不抛
                //var type3 = assembly.GetType("Student", true);
                //var type4 = assembly.GetType("Student", false);
                //var type5 = assembly.GetType("Student", true, true); 
                #endregion

                #endregion

                #region 反射 创建对象

                #region assembly.CreateInstance 创建对象
                //Student中只有一个无参的构造函数，调用assembly中的CreateInstance可以直接调用Student中的构造函数
                object oStudent = assembly.CreateInstance("BLL.One.Student");
                //Qiao中只有一个有参的构造函数，调用assembly中的CreateInstance，找不到无参的构造函数，直接抛异常
                //object oQiao = assembly.CreateInstance("BLL.One.Qiao");
                #endregion

                ///使用 Activator.CreateInstance 创建对象的实例
                ///无参的构造函数
                ///有参的构造函数
                ///私有构造函数
                ///泛型的构造函数
                #region Activator.CreateInstance 创建对象的实例

                #region 无参的构造函数
                ///无参的构造函数
                Type tempType = assembly.GetType(bllConfig + ".Student");
                object objStudent = Activator.CreateInstance(tempType);
                #endregion

                #region 有参的构造函数
                //有参的构造函数
                tempType = assembly.GetType(bllConfig + ".Qiao");
                //tempType
                object objQiao = Activator.CreateInstance(tempType, new object[] { "name" });
                #endregion

                #region 私有构造函数
                //私有构造函数
                tempType = assembly.GetType(bllConfig + ".AnSheng");
                //创建对象的实例的时候可以指定创建 私有构造函数的实例
                object objAnSheng1 = Activator.CreateInstance(tempType, true);
                //直接抛异常，因为AnSheng 中的构造函数是私有的
                ///object objAnSheng2 = Activator.CreateInstance(tempType, false); 
                #endregion

                #region 泛型的构造函数
                ///泛型无参构造函数
                tempType = assembly.GetType(bllConfig + ".GenericQiao`3");
                Type typeNew = tempType.MakeGenericType(typeof(int), typeof(int), typeof(int));
                object objGenericQiao = Activator.CreateInstance(typeNew);

                ///泛型有参构造函数
                tempType = assembly.GetType(bllConfig + ".GenericQiao`3");
                typeNew = tempType.MakeGenericType(typeof(int), typeof(int), typeof(int));
                object objGenericQiao1 = Activator.CreateInstance(typeNew, new object[] { 1, 2, 3 });

                #endregion

                #endregion

                #endregion

                #region 反射 调用方法

                ///通过反射调用
                ///无参方法
                ///私有方法
                ///实例方法
                ///静态方法
                ///泛型方法
                ///
                ///方法重载
                ///
                ///获取到这个类型
                Type type = null;

                #region 调用无参方法
                type = assembly.GetType(bllConfig + ".Qiao");
                //获取到这个方法
                var mi = type.GetMethod("GetQiao");
                mi.Invoke(objQiao, null);
                #endregion

                #region 调用私有方法
                type = assembly.GetType(bllConfig + ".Qiao");
                //获取到这个方法
                mi = type.GetMethod("GetPrivateString", BindingFlags.NonPublic | BindingFlags.Instance);
                mi.Invoke(objQiao, null);
                #endregion

                #region 调用有参有返回值的方法
                type = assembly.GetType(bllConfig + ".Qiao");
                mi = type.GetMethod("GetQiaoString", new Type[] { typeof(string) });
                var tempStringObj = mi.Invoke(objQiao, new object[] { "这是一个有参，有返回值的方法" });
                var tempString = (string)tempStringObj;
                Console.WriteLine(tempString);
                #endregion

                #region 调用静态方法
                type = assembly.GetType(bllConfig + ".Qiao");
                mi = type.GetMethod("GetQiaoStatic");
                var tempGetQiaoStatic1 = mi.Invoke(objQiao, null);
                var tempGetQiaoStatic2 = mi.Invoke(null, null);
                var tempString1 = (string)tempGetQiaoStatic1;
                Console.WriteLine(tempString);
                #endregion

                #region 调用泛型方法
                type = assembly.GetType(bllConfig + ".Qiao");
                //获取到这个方法
                mi = type.GetMethod("GetGeneric");
                mi = mi.MakeGenericMethod(typeof(int), typeof(int), typeof(int));
                mi.Invoke(objQiao, new object[] { 1, 2, 3 });
                #endregion

                #region 各种重载

                type = assembly.GetType(bllConfig + ".Student");

                #region GetStudent 中无参方法
                mi = type.GetMethod("GetStudent", new Type[] { });
                mi.Invoke(objStudent, null);
                #endregion

                #region GetStudent 中int类型重载方法
                mi = type.GetMethod("GetStudent", new Type[] { typeof(int) });
                mi.Invoke(objStudent, new object[] { 123 });
                #endregion

                #region GetStudent 中int? 可空类型重载方法调用 2种
                mi = type.GetMethod("GetStudent", new Type[] { typeof(int?) });
                mi.Invoke(objStudent, new object[] { null });
                mi.Invoke(objStudent, new object[] { 123 });
                #endregion

                #region GetStudent 中string 类型重载方法调用 2种
                mi = type.GetMethod("GetStudent", new Type[] { typeof(string) });
                mi.Invoke(objStudent, new object[] { "123" });
                mi.Invoke(objStudent, new object[] { null });
                #endregion

                #region GetStudent 中可选参数 类型如果不传编译报错，如果传null，则接受的时候参数就是null
                mi = type.GetMethod("GetStudent", new Type[] { typeof(string), typeof(string) });
                mi.Invoke(objStudent, new object[] { "123", null });
                mi.Invoke(objStudent, new object[] { "123", "321" });
                #endregion

                #region 泛型重载
                //mi = type.GetMethod("GetStudent",new Type[] { typeof(int)});
                //mi = mi.MakeGenericMethod(typeof(int));
                //mi.Invoke(objStudent, new object[] { 123 });
                #endregion

                #endregion

                #endregion
            }

            #region 反射 字段和属性
            ///通过反射获取属性的名称，属性的值，属性的类型，属性的特性
            {
                Type type = typeof(StudentEntity);
                object objStudentEntity = Activator.CreateInstance(type);

                #region Type中的所有属性
                {
                    ///通过反射获取类型的访问修饰符
                    var temp39 = type.IsNestedPrivate;
                    var temp40 = type.IsNestedPublic;
                    var temp41 = type.IsNotPublic;
                    var temp44 = type.IsPublic;
                    ///获取一个指示 System.Type 是否可由程序集之外的代码访问的值。
                    var temp53 = type.IsVisible;


                    ///通过反射判断该类型是否是 某个类型
                    ///获取一个值，通过该值指示 System.Type 是否为抽象的并且必须被重写。
                    var temp15 = type.IsAbstract;
                    ///获取一个值，该值指示类型是否为数组。
                    var temp17 = type.IsArray;
                    ///获取一个值，通过该值指示 System.Type 是否是一个类或委托；即，不是值类型或接口。
                    var temp21 = type.IsClass;
                    ///获取一个值，该值指示当前的 System.Type 是否表示枚举。
                    var temp25 = type.IsEnum;
                    ///获取一个值，该值指示当前 System.Type 是否表示泛型类型或方法的定义中的类型参数。
                    var temp27 = type.IsGenericParameter;
                    if (temp27)
                    {
                        //type.IsGenericParameter 必须为true才能使用
                        var temp07 = type.DeclaringMethod;
                        var temp10 = type.GenericParameterAttributes;
                        var temp11 = type.GenericParameterPosition;
                    }
                    ///获取一个值，该值指示当前类型是否是泛型类型。
                    var temp28 = type.IsGenericType;
                    ///获取一个值，该值指示当前 System.Type 是否表示可以用来构造其他泛型类型的泛型类型定义。
                    var temp29 = type.IsGenericTypeDefinition;
                    ///获取一个值，通过该值指示 System.Type 是否是一个接口；即，不是类或值类型。
                    var temp31 = type.IsInterface;
                    ///获取一个值，该值指示 System.Type 是否声明为密封的。
                    var temp45 = type.IsSealed;


                    ///获取类型上的属性
                    var temp01 = type.Assembly;
                    var temp02 = type.AssemblyQualifiedName;
                    var temp03 = type.Attributes;
                    //获取到该类型的直接父类
                    var temp04 = type.BaseType;
                    var temp05 = type.ContainsGenericParameters;
                    var temp06 = type.CustomAttributes;

                    var temp08 = type.DeclaringType;
                    var temp09 = type.FullName;
                    var temp12 = type.GenericTypeArguments;
                    var temp13 = type.GUID;
                    var temp14 = type.HasElementType;
                    var temp16 = type.IsAnsiClass;
                    var temp18 = type.IsAutoClass;
                    var temp19 = type.IsAutoLayout;
                    var temp20 = type.IsByRef;
                    var temp22 = type.IsCOMObject;
                    var temp23 = type.IsConstructedGenericType;
                    var temp24 = type.IsContextful;
                    var temp26 = type.IsExplicitLayout;
                    var temp30 = type.IsImport;
                    var temp32 = type.IsLayoutSequential;
                    var temp33 = type.IsMarshalByRef;
                    var temp34 = type.IsNested;
                    var temp35 = type.IsNestedAssembly;
                    var temp36 = type.IsNestedFamANDAssem;
                    var temp37 = type.IsNestedFamily;
                    var temp38 = type.IsNestedFamORAssem;
                    var temp42 = type.IsPointer;
                    var temp43 = type.IsPrimitive;
                    var temp46 = type.IsSecurityCritical;
                    var temp47 = type.IsSecuritySafeCritical;
                    var temp48 = type.IsSecurityTransparent;
                    var temp49 = type.IsSerializable;
                    var temp50 = type.IsSpecialName;
                    var tmep51 = type.IsUnicodeClass;
                    var temp52 = type.IsValueType;
                    var temp54 = type.MemberType;
                    var temp55 = type.MetadataToken;
                    var temp56 = type.Module;
                    var temp57 = type.Name;
                    var temp58 = type.Namespace;
                    var temp59 = type.ReflectedType;
                    var temp60 = type.StructLayoutAttribute;
                    var temp61 = type.TypeHandle;
                    var temp62 = type.TypeInitializer;
                    var temp63 = type.UnderlyingSystemType;
                }
                #endregion

                #region 获取类型中所有的属性 属性的名称，属性的值，属性的类型，属性的特性
                {
                    foreach (PropertyInfo item in type.GetProperties())
                    {
                        var desc = ((DescriptionAttribute)Attribute.GetCustomAttribute(item, typeof(DescriptionAttribute)));
                        string des = " 空 ";
                        if (desc != null)
                        {
                            des = desc.Description;// 属性值
                        }
                        Console.WriteLine("属性名称：{0}，属性值：{1}，属性类型：{2},属性描述：{3}", item.Name, item.GetValue(objStudentEntity), item.PropertyType, des);

                    }
                }
                #endregion

                #region 获取类型中所有的特性
                {
                    foreach (Attribute item in type.GetCustomAttributes())
                    {
                        Console.WriteLine(item.Match(new QiaoAttribute()) + "   " + item.IsDefaultAttribute());
                    }
                }
                #endregion

            }

            #endregion


            Console.ReadLine();
        }
    }
}
